// AJAX请求前将CSRFToken值放入header中
var _ajaxBeforeSendFun = function(xhr){
    var CSRFToken = $("meta[name='_csrf']").attr("content");
    xhr.setRequestHeader("CSRFToken", CSRFToken);
};
WICONF.request = {
    showloading: false,
    errorMsg: '网络异常，请稍后再试!',
    ajaxOpts_beforeSend: _ajaxBeforeSendFun// $.ajax() 中的 beforeSend(xhr, settings)
};
/**
 * @widoc $.request
 * @namespace aux
 * @des 请求数据，要求后台返回的数据结构：
 *   - success {boolean}
 *   - msg {string} success=false 时的错误提示
 *   - data 将作为 onSuccess 的参数
 * 组件配置，在使用组件前调用：
 <pre class="des-conf"> $.setWiConf('request',{
    showloading: false,
    errorMsg: '网络异常，请稍后再试!',
    ajaxOpts_beforeSend: _ajaxBeforeSendFun// $.ajax() 中的 beforeSend(xhr, settings)
 });</pre>
 * @type function
 * @param {object} opts
 * @param {object} opts.ajaxOpts 调用 $.ajax() 请求时的自定义配置，详情参考 jQuery API。
 *   常用属性如下：
 *   - opts.ajaxOpts.url {string} 请求地址
 *   - opts.ajaxOpts.data {object|string} 请求参数，简单参数传 object，复杂参数应先 JSON.stringify()
 * @param {function=} opts.onSuccess(data) 成功回调(参数：数据集合 result.data)，请求成功且 request.success=true 时触发。
 * @param {function=} opts.onError(oErrInfo) 异常回调，请求失败或 request.success!=true 时触发。
 *   - oErrInfo {object}
 *   oErrInfo.type = 'success' 时，oErrInfo 中还包含：msg, result, textStatus, jqXHR
 *   oErrInfo.type = 'error' 时，oErrInfo 中还包含：msg, errorThrown, textStatus, jqXHR
 * @param {boolean|object=} opts.showloading 请求时是否显示 loading 动画，值为 object 时，作为 $.showLoading(opts) 的参数。默认值通过 $.setWiConf() 配置
 * @param {boolean=} opts.argToJson 请求时是否附加如下参数 contentType:"application/json"，默认为 false。
 * @param {string=} opts.errorMsg 该请求默认的错误提示信息，默认值通过 $.setWiConf() 配置。
 * @return {object} jqXHR 实现了 promise 接口的 jqXHR 对象，详见 jQuery API
 */
$.request = function(opts){
    var CONF = WICONF.request;// 全局配置
    opts = $.extend({
        ajaxOpts: {},
        onSuccess: $.noop,
        //onError: function(oErrInfo),// 未定义时需使用默认操作，故不应设置默认值，在 fHandleErr() 中判断
        showloading: CONF.showloading,
        argToJson: false,
        errorMsg: CONF.errorMsg
    }, opts);

    var oAjaxOpts,// 用户自定义的 $.ajax() 配置
        fSucCus, fErrCus;// success, error 将在组件中重写，因此需要缓存用户自定义的实现

    // 异常处理函数
    var fHandleErr = function(oErrInfo){
        // oErrInfo.type = 'success' 时，oErrInfo 中还包含：msg, result, textStatus, jqXHR
        // oErrInfo.type = 'error' 时，oErrInfo 中还包含：msg, errorThrown, textStatus, jqXHR
        var fOnError = opts.onError,
            sMsg = oErrInfo.msg;
        if(fOnError){
            fOnError(oErrInfo);
        }
        else{
            sMsg && $.showAlert(sMsg);
        }
    };

    // 发起请求
    var fRequest = function(){
        var oShowloading = opts.showloading,
            sLoadingKey;// showLoading() 时生成的 loading 对应的 key
        var fSuccess = function(result, textStatus, jqXHR){
            sLoadingKey && $.hideLoading({key: sLoadingKey});// 传入 key，关闭对应的 loading
            if(result.success){
                opts.onSuccess(result.data);
            }
            else{
                fHandleErr({
                    type: 'success',
                    msg: result.msg || opts.errorMsg,
                    result: result,
                    textStatus: textStatus,
                    jqXHR: jqXHR
                });
            }
            fSucCus && fSucCus(result, textStatus, jqXHR);
        };
        var fError = function(jqXHR, textStatus, errorThrown){
            sLoadingKey && $.hideLoading({key: sLoadingKey});// 传入 key，关闭对应的 loading
            fHandleErr({
                type: 'error',
                msg: opts.errorMsg,
                errorThrown: errorThrown,
                textStatus: textStatus,
                jqXHR: jqXHR
            });
            fErrCus && fErrCus(jqXHR, textStatus, errorThrown);
        };

        // 开启 loading 动画
        if(oShowloading){
            sLoadingKey = $.showLoading(oShowloading).key;// 记录 key，以关闭对应的 loading
        }
        return $.ajax($.extend({
            beforeSend: CONF.ajaxOpts_beforeSend,
            success: fSuccess,
            error: fError,
            type: 'post',
            dataType: 'json'
        }, oAjaxOpts));
    };

    var fInit = function(){
        oAjaxOpts = opts.ajaxOpts;
        if(opts.argToJson){
            oAjaxOpts.contentType = "application/json";
        }
        fSucCus = oAjaxOpts.success;
        fErrCus = oAjaxOpts.error;
        delete oAjaxOpts.success;
        delete oAjaxOpts.error;
    };

    fInit();
    return fRequest();// 返回实现了 promise 接口的 jqXHR 对象
};